package top.juc.plugin.idea.openfeignx.util;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.scanner.ScannerException;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

public class ConfigParseUtils {
    private static final Logger logger = Logger.getInstance(ConfigParseUtils.class);

    public static ConcurrentHashMap<Module, String> parseConfig(ConcurrentHashMap<Module, List<VirtualFile>> moduleConfigMap) {
        ConcurrentHashMap<Module, String> moduleServiceNameMap = new ConcurrentHashMap<>(16);
        moduleConfigMap.forEach((module, virtualFiles) -> {
            for (VirtualFile virtualFile : virtualFiles) {
                Object applicationName = readNameByConfig(virtualFile);
                if (Objects.nonNull(applicationName)) {
                    //字符串替换: weeget-bullet-marketing-rest${SERVICE_FORS:} -> weeget-bullet-marketing-rest
                    String key = applicationName.toString().replaceAll("\\$\\{[^}]*\\}", "");
                    moduleServiceNameMap.put(module, key);
                    return;
                }
            }
        });
        return moduleServiceNameMap;
    }


    private static Object readNameByConfig(VirtualFile configurationFile) {
        FileType fileType = configurationFile.getFileType();
        // yml ,yaml 后缀读取支持
        if (FileTypes.YAML_SUFFIX.contains(fileType.getDefaultExtension())) {
            // 读取 yml 文件内容
            String content = null;
            try (InputStream inputStream = configurationFile.getInputStream()) {
                content = IOUtils.toString(inputStream);
                // 首次读取, 可能存在 @变量@ 的场景, 在捕获异常后, 替换掉这种异常字符串, 然后再次读取别名
                return readClassesFromYaml(configurationFile.getName(), content);
            } catch (IOException e) {
                logger.error("read alias exception, fileName:" + configurationFile.getName(), e);
            } catch (ScannerException e) {
                if (content != null) {
                    // 通过正则替换掉不符合 yml 格式的字符串, 再次尝试读取别名
                    final String contentReplaced = content.replaceAll("@.*@", "MYBATISX_REPLACE");
                    try {
                        return readClassesFromYaml(configurationFile.getName(), contentReplaced);
                    } catch (ScannerException e2) {
                        // 存在 @变量@ 的情况, 暂时忽略这种情况
                        logger.debug("yml parse fail, fileName: {}", configurationFile.getName(), e2);
                    }
                }
            }
        }
        // properties 读取支持
        if (fileType.getDefaultExtension().equals(FileTypes.PROPERTIES_SUFFIX)) {
            return readClassesFromProperties(configurationFile);
        }
        return null;
    }

    private static Object readClassesFromProperties(VirtualFile configurationFile) {
        Properties properties = new Properties();
        try (InputStream inputStream = configurationFile.getInputStream()) {
            properties.load(inputStream);
            return findTypeAliasesPackageByProperties(properties);
        } catch (IOException e) {
            logger.error("read alias exception, fileName: " + configurationFile.getName(), e);
        }
        return null;
    }

    private static Object findTypeAliasesPackageByProperties(Properties properties) {
        return properties.getProperty("spring.application.name");
    }

    private static Object readClassesFromYaml(String fileName, String content) {
        Yaml yaml = new Yaml();
        try {
            Iterable<Object> objects = yaml.loadAll(content);
            for (Object object : objects) {
                Object config = findSpringApplicationName(object);
                if (config != null) {
                    return config;
                }
            }
        } catch (Exception e) {
            // https://gitee.com/baomidou/MybatisX/issues/I58K0P  yaml.loadAll(content).next 会导致git流程的空指针
            // 错误的 yml 文件, 不予支持
            logger.info("yml parse fail, fileName: " + fileName, e);
        }
        return null;
    }

    private static Object findSpringApplicationName(Object config) {
        Object spring = findConfig(config, Collections.singletonList("spring"));
        if (spring == null) {
            return null;
        }
        Object application = findConfig(spring, Collections.singletonList("application"));
        if (application == null) {
            return null;
        }
        return findConfig(application, Collections.singletonList("name"));
    }

    private static Object findConfig(Object config, List<String> searchConfigList) {
        if (config instanceof Map) {
            Map jsonObject = (Map) config;
            for (String search : searchConfigList) {
                Object result = jsonObject.get(search);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }
}
